#include <linux/init.h>
#include <linux/module.h>
#include <linux/miscdevice.h>
#include <linux/fs.h>
#include <linux/uaccess.h>
#include <linux/io.h>
#include <linux/of.h>
#include <linux/of_device.h>
#include <linux/of_address.h>
#include <linux/of_irq.h>
#include <linux/interrupt.h>
#include <linux/platform_device.h>
#include <linux/of_gpio.h>
#include <linux/wait.h>
#include <linux/kthread.h>
#include <linux/delay.h>

#define DEVICE_NAME "key_driver"
#define IOCTL_CMD_EXAMPLE 0x01  // 示例 IOCTL 命令
static struct tasklet_struct key_test_tasklet_1;

static DECLARE_WAIT_QUEUE_HEAD(wait_queue); // 声明等待队列头
static int flag = 0;                        // 标志位，表示是否有事件发生
static struct task_struct *consumer_thread; // 消费者线程

// 全局数据缓冲区
static char data[32] = {0};
// 保存中断号
static unsigned int irq_number;

//模拟按键作为开关作用
static unsigned int key_val = 0;

// tasklet 处理函数
void key_test_tasklet_func_1(unsigned long data)
{   
    pr_info("Key 1 tasklet processing················\n");
    pr_info("Current data: %lu\n", data); 
    // 执行按键1的后续任务
}

// 消费者线程函数
static int consumer_func(void *data) {
    while (!kthread_should_stop()) {
        pr_info("Consumer: Waiting for event...\n");

        // 等待事件发生
        wait_event_interruptible(wait_queue, flag != 0);

        if (flag) {
            pr_info("Consumer: Event detected, processing data... key_val = %d\n", key_val);

            // 处理数据
            msleep(1000); // 模拟处理耗时

            // 重置标志位
            flag = 0;
        }
    }

    pr_info("Consumer: Exiting.\n");
    return 0;
}

// 中断处理函数（模拟生产者）
static irqreturn_t irq_handler(int irq, void *dev_id) {

    pr_info("Producer: Interrupt occurred, waking up the consumer. IRQ number: %d\n", irq);
    // 每次按键按下时状态翻转
    key_val = !key_val;

    // 设置事件标志
    flag = 1;

    // 唤醒等待队列
    wake_up_interruptible(&wait_queue);

    // 调度 Tasklet
    tasklet_schedule(&key_test_tasklet_1);
    
    return IRQ_HANDLED;
}


// 设备打开函数
static int misc_open(struct inode *inode, struct file *file) {
    pr_info("%s: Device opened\n", DEVICE_NAME);
    return 0;
}

// 设备关闭函数
static int misc_close(struct inode *inode, struct file *file) {
    pr_info("%s: Device closed\n", DEVICE_NAME);
    return 0;
}

// 设备读函数
static ssize_t misc_read(struct file *file, char __user *buf, size_t count, loff_t *ppos) {
    size_t len = strnlen(data, sizeof(data));

    if (*ppos >= len)
        return 0;

    if (copy_to_user(buf, data, len)) {
        pr_err("%s: Failed to copy data to user space\n", DEVICE_NAME);
        return -EFAULT;
    }

    *ppos += len;
    pr_info("%s: Device read: %s\n", DEVICE_NAME, data);
    return len;
}

// 设备写函数
static ssize_t misc_write(struct file *file, const char __user *buf, size_t count, loff_t *ppos) {
    if (count >= sizeof(data)) {
        pr_err("%s: Write data too large\n", DEVICE_NAME);
        return -EINVAL;
    }

    memset(data, 0, sizeof(data));

    if (copy_from_user(data, buf, count)) {
        pr_err("%s: Failed to copy data from user space\n", DEVICE_NAME);
        return -EFAULT;
    }

    pr_info("%s: Device write: %s\n", DEVICE_NAME, data);
    return count;
}

// IOCTL 控制函数
static long misc_ioctl(struct file *file, unsigned int cmd, unsigned long arg) {
    switch (cmd) {
    case IOCTL_CMD_EXAMPLE:
        pr_info("%s: IOCTL example command executed\n", DEVICE_NAME);
        break;
    default:
        pr_err("%s: Invalid IOCTL command\n", DEVICE_NAME);
        return -EINVAL;
    }
    return 0;
}

// 文件操作结构体
static const struct file_operations misc_fops = {
    .owner = THIS_MODULE,
    .open = misc_open,
    .release = misc_close,
    .read = misc_read,
    .write = misc_write,
    .unlocked_ioctl = misc_ioctl,
};

// 杂项设备结构体
static struct miscdevice misc_dev = {
    .minor = MISC_DYNAMIC_MINOR,
    .name = DEVICE_NAME,
    .fops = &misc_fops,
};

// 平台设备匹配表
static const struct of_device_id misc_of_match[] = {
    { .compatible = "key0-test", },
    {},
};
MODULE_DEVICE_TABLE(of, misc_of_match);

// 平台设备探测函数
static int misc_probe(struct platform_device *pdev) {

    struct device_node *node = pdev->dev.of_node;
    int gpio_num;

    if (!node) {
    pr_err("Failed to find device node\n");
    return -ENODEV;
    }

    // 打印设备树节点的名称
    pr_info("Found device node: %s\n", node->full_name);

    // 1. 获取GPIO引脚编号
    gpio_num = of_get_named_gpio(node, "key1-gpio", 0);
    if (gpio_num < 0) {
        pr_err("Failed to get gpio_num\n");
    return -ENODEV;
    }
    pr_info("gpio_num: %d\n", gpio_num);

    // 2. 设置GPIO方向为输入，并启用上拉电阻
    gpio_direction_input(gpio_num);

    // 3. 从设备树节点获取中断号
    // irq_number = gpio_to_irq(gpio_num); // 方法1 将 GPIO 编号（通常是硬件抽象层的逻辑编号）映射为内核中对应的 IRQ 中断号
    irq_number = irq_of_parse_and_map(node, 0); // 方法2 从设备树中解析中断信息并映射为内核中断号
    if (!irq_number) {
        pr_err("%s: Failed to parse and map IRQ\n", DEVICE_NAME);
        return -EINVAL;
    }


    // 4. 注册中断 上升沿触发中断
    if (request_irq(irq_number, irq_handler, IRQF_TRIGGER_RISING, DEVICE_NAME, &misc_dev) < 0) {
        pr_err("%s: Failed to request IRQ\n", DEVICE_NAME);
        return -EBUSY;
    }

    pr_info("%s: Registered IRQ %d\n", DEVICE_NAME, irq_number);
    // 初始化 tasklet
    tasklet_init(&key_test_tasklet_1, key_test_tasklet_func_1, 5);

    // 创建消费者线程
    consumer_thread = kthread_run(consumer_func, NULL, "consumer_thread");
    if (IS_ERR(consumer_thread)) {
        free_irq(irq_number, (void *)irq_handler);
        pr_err("Failed to create consumer thread.\n");
        return PTR_ERR(consumer_thread);
    }
    // 注册杂项设备
    return misc_register(&misc_dev);
}

// 平台设备移除函数
static int misc_remove(struct platform_device *pdev) {
    // 停止消费者线程
    if (consumer_thread) {
        // 设置事件标志
        flag = 1;
        // 唤醒等待队列，防止卸载时消费者线程还陷入阻塞状态
        wake_up_interruptible(&wait_queue);
        kthread_stop(consumer_thread);
    }
    // 注销中断
    free_irq(irq_number, &misc_dev);
    // 清理 tasklet
    tasklet_kill(&key_test_tasklet_1);
    misc_deregister(&misc_dev);
    // pr_info("%s: Device removed\n", DEVICE_NAME);
    return 0;
}

// 平台驱动结构体
static struct platform_driver misc_driver = {
    .driver = {
        .name = DEVICE_NAME,
        .of_match_table = misc_of_match,
    },
    .probe = misc_probe,
    .remove = misc_remove,
};

// 模块初始化函数
static int __init misc_init(void) {
    return platform_driver_register(&misc_driver);
}

// 模块卸载函数
static void __exit misc_exit(void) {
    platform_driver_unregister(&misc_driver);
    pr_info("%s: Device removed\n", DEVICE_NAME);
}

module_init(misc_init);
module_exit(misc_exit);

MODULE_LICENSE("GPL");
MODULE_AUTHOR("Your Name");
MODULE_DESCRIPTION("A simple misc device driver with device tree support and interrupt handling");
MODULE_VERSION("1.0");
